package org.datascooter.utils;

import java.io.File;
import java.io.FileInputStream;
import java.text.SimpleDateFormat;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.datascooter.utils.policy.SequencePolicy;
import org.datascooter.utils.policy.SnipPolicy;
import org.datascooter.utils.policy.TableValidationPolicy;

/**
 * Common container for datascooter prefereces
 * 
 * @author nemo
 * 
 */
public class DSSettings {

	private static Properties props;
	private static String filePath;
	private static int statementCasheSize = 50;
	private static Integer connectionPoolSize = 5;
	private static Integer waitConnectionTimeout = 60;
	private static int batchSize = 10000;
	private static SnipPolicy snipPolicy = SnipPolicy.EXECUTE;
	private static Integer defaultStringLength = 1024;
	private static boolean useDefaultProvider = true;
	private static int defaultBlobLength = 10000;
	private static int defaultClobLength = 10000;
	private static TableValidationPolicy tableValidationPolicy = TableValidationPolicy.BY_BUNDLE_CHANGE;
	private static SequencePolicy sequencePolicy = SequencePolicy.GLOBAL;
	private static String tablePrefix = "";
	private static String columnPrefix = "";
	private static String dateTimeFormat = "yyyy-MM-dd HH:mm:ss";
	private static SimpleDateFormat format = new SimpleDateFormat(dateTimeFormat);
	private static int transactionIsolation = 2;
	private static int resultSetHoldability = 2;
	private static boolean verifyTables = false;
	private static boolean logDDL = false;
	private static boolean useFieldAttributes = false;
	private static boolean buildForeignKeys = false;
	private static boolean trimExtraString = true;
	private static boolean verifyPartOfPrimaryKeys = true;
	private static boolean createUtilityTables = true;
	private static boolean useIdInCrossTables = true;

	public static void init(String filePathIn) {
		filePath = filePathIn;
		load();
	}

	private static void logConfig(String message) {
		Logger.getLogger(DSSettings.class.getName()).config(message);
	}

	public static void load() {
		if (filePath != null && new File(filePath).exists()) {
			try {
				FileInputStream inStream = new FileInputStream(filePath);
				try {
					props = new Properties();
					props.load(inStream);
					statementCasheSize = getInteger("statementCasheSize", statementCasheSize);
					connectionPoolSize = getInteger("connectionPoolSize", connectionPoolSize);
					waitConnectionTimeout = getInteger("waitConnectionTimeout", waitConnectionTimeout);
					batchSize = getInteger("batchSize", batchSize);
					defaultStringLength = getInteger("defaultStringLength", defaultStringLength);
					defaultBlobLength = getInteger("defaultBlobLength", defaultBlobLength);
					defaultClobLength = getInteger("defaultClobLength", defaultClobLength);
					useDefaultProvider = getBooleanTrue("useDefaultProvider");
					verifyTables = getBooleanFalse("verifyTables");
					logDDL = getBooleanFalse("logDDL");
					useFieldAttributes = getBooleanFalse("useFieldAttributes");
					buildForeignKeys = getBooleanFalse("buildForeignKeys");
					verifyPartOfPrimaryKeys = getBooleanTrue("verifyPartOfPrimaryKeys");
					trimExtraString = getBooleanFalse("trimExtraString");
					tablePrefix = getString("tablePrefix", tablePrefix);
					columnPrefix = getString("columnPrefix", columnPrefix);
					dateTimeFormat = getString("dateTimeFormat", dateTimeFormat);
					transactionIsolation = getInteger("transactionIsolation", 2);
					resultSetHoldability = getInteger("resultSetHoldability", 2);
					createUtilityTables = getBooleanTrue("createUtilityTables");
					useIdInCrossTables = getBooleanTrue("useIdInCrossTables");
					try {
						tableValidationPolicy = TableValidationPolicy.valueOf(getString("tableValidationPolicy"));
					} catch (Exception e) {
						tableValidationPolicy = TableValidationPolicy.BY_BUNDLE_CHANGE;
					}
					format = new SimpleDateFormat(dateTimeFormat);
					if (defaultBlobLength <= 0) {
						defaultBlobLength = 10000;
						logConfig("***Default String Length  " + defaultBlobLength);
					}
					if (defaultClobLength <= 0) {
						defaultClobLength = 10000;
						logConfig("***Default String Length  " + defaultClobLength);
					}
					if (defaultStringLength <= 0) {
						defaultStringLength = 512;
						logConfig("***Default String Length  " + defaultStringLength);
					}
					if (getString("snipPolicy").length() > 0)
						snipPolicy = SnipPolicy.valueOf(getString("snipPolicy"));
					if (getString("sequencePolicy").length() > 0)
						sequencePolicy = SequencePolicy.valueOf(getString("sequencePolicy"));
					if (connectionPoolSize <= 0) {
						connectionPoolSize = 5;
						logConfig("***Default connectionPoolSize  " + connectionPoolSize);
					}
					if (waitConnectionTimeout <= 0) {
						waitConnectionTimeout = 60;
						logConfig("***Default waitConnectionTimeout  " + waitConnectionTimeout);
					}
					if (batchSize <= 0) {
						batchSize = 1000;
						logConfig("***Default batchSize  " + batchSize);
					}
				} finally {
					inStream.close();
				}
			} catch (Exception e) {
				Logger.getLogger(DSSettings.class.getName()).log(Level.SEVERE, "***Error by load Datascooter settings", e);
			}
		} else {
			Logger.getLogger(DSSettings.class.getName())
				.info("*** Not found file datascooter.properties - let's use the default values  " + filePath);
		}
		logConfig("***ConnectionPoolSize  " + connectionPoolSize + "   waitConnectionTimeout  " + waitConnectionTimeout + "   batchSize  "
			+ batchSize);
	}

	/**
	 * Returns by default true
	 * 
	 * @param propName
	 * @return
	 */
	public static boolean getBooleanTrue(String propName) {
		return Boolean.valueOf(props.getProperty(propName, "true"));
	}

	/**
	 * Returns by default false
	 * 
	 * @param propName
	 * @return
	 */
	public static boolean getBooleanFalse(String propName) {
		return Boolean.valueOf(props.getProperty(propName, "false"));
	}

	public static Integer getInteger(String propName, int defaultValue) {
		return Integer.valueOf(props.getProperty(propName, defaultValue + ""));
	}

	public static String getString(String propName) {
		return props.getProperty(propName, "");
	}

	public static String getString(String propName, String defaultValue) {
		return props.getProperty(propName, defaultValue);
	}

	public static int getConnectionPoolSize() {
		return connectionPoolSize;
	}

	public static int getWaitConnectionTimeout() {
		return waitConnectionTimeout;
	}

	public static int getBatchSize() {
		return batchSize;
	}

	public static SnipPolicy getSnipPolicy() {
		return snipPolicy;
	}

	public static int getDefaultStringLength() {
		return defaultStringLength;
	}

	public static int getDefaultBlobLength() {
		return defaultBlobLength;
	}

	public static int getDefaultClobLength() {
		return defaultClobLength;
	}

	public static boolean isUseDefaultProvider() {
		return useDefaultProvider;
	}

	public static TableValidationPolicy getTableValidationPolicy() {
		return tableValidationPolicy;
	}

	public static void setConnectionPoolSize(Integer connectionPoolSize) {
		DSSettings.connectionPoolSize = connectionPoolSize;
	}

	public static void setWaitConnectionTimeout(Integer waitConnectionTimeout) {
		DSSettings.waitConnectionTimeout = waitConnectionTimeout;
	}

	public static void setBatchSize(int batchSize) {
		DSSettings.batchSize = batchSize;
	}

	public static void setSnipPolicy(SnipPolicy snipPolicy) {
		DSSettings.snipPolicy = snipPolicy;
	}

	public static void setDefaultStringLength(Integer defaultStringLength) {
		DSSettings.defaultStringLength = defaultStringLength;
	}

	public static void setUseDefaultProvider(boolean useDefaultProvider) {
		DSSettings.useDefaultProvider = useDefaultProvider;
	}

	public static void setDefaultBlobLength(int defaultBlobLength) {
		DSSettings.defaultBlobLength = defaultBlobLength;
	}

	public static void setDefaultClobLength(int defaultClobLength) {
		DSSettings.defaultClobLength = defaultClobLength;
	}

	public static void setTableValidationPolicy(TableValidationPolicy tableValidationPolicy) {
		DSSettings.tableValidationPolicy = tableValidationPolicy;
	}

	public static boolean isVerifyTables() {
		return verifyTables;
	}

	public static void setVerifyTables(boolean verifyTables) {
		DSSettings.verifyTables = verifyTables;
	}

	public static boolean isLogDDL() {
		return logDDL;
	}

	public static void setLogDDL(boolean logDDL) {
		DSSettings.logDDL = logDDL;
	}

	public static SequencePolicy getSequencePolicy() {
		return sequencePolicy;
	}

	public static boolean useSequence() {
		return !DSSettings.sequencePolicy.equals(SequencePolicy.NO_SEQUENCES);
	}

	public static void setSequencePolicy(SequencePolicy sequencePolicy) {
		DSSettings.sequencePolicy = sequencePolicy;
	}

	public static String getTablePrefix() {
		return tablePrefix;
	}

	public static void setTablePrefix(String tablePrefix) {
		DSSettings.tablePrefix = tablePrefix;
	}

	public static String getColumnPrefix() {
		return columnPrefix;
	}

	public static void setFieldPrefix(String fieldPrefix) {
		DSSettings.columnPrefix = fieldPrefix;
	}

	public static String getDateTimeFormat() {
		return dateTimeFormat;
	}

	public static void setDateTimeFormat(String dateTimeFormat) {
		DSSettings.dateTimeFormat = dateTimeFormat;
		format = new SimpleDateFormat(dateTimeFormat);
	}

	public static String getFilePath() {
		return filePath;
	}

	public static int getStatementCasheSize() {
		return statementCasheSize;
	}

	public static void setStatementCasheSize(int statementCasheSize) {
		DSSettings.statementCasheSize = statementCasheSize;
	}

	public static void setColumnPrefix(String columnPrefix) {
		DSSettings.columnPrefix = columnPrefix;
	}

	public static boolean isUseFieldAttributes() {
		return useFieldAttributes;
	}

	public static void setUseFieldAttributes(boolean useFieldAttributes) {
		DSSettings.useFieldAttributes = useFieldAttributes;
	}

	public static boolean isBuildForeignKeys() {
		return buildForeignKeys;
	}

	public static void setBuildForeignKeys(boolean buildForeignKeys) {
		DSSettings.buildForeignKeys = buildForeignKeys;
	}

	public static SimpleDateFormat getFormat() {
		return format;
	}

	public static int getTransactionIsolation() {
		return transactionIsolation;
	}

	public static int getResultSetHoldability() {
		return resultSetHoldability;
	}

	public static boolean isTrimExtraString() {
		return trimExtraString;
	}

	public static void setTrimExtraString(boolean trimExtraString) {
		DSSettings.trimExtraString = trimExtraString;
	}

	public static boolean isVerifyPartOfPrimaryKeys() {
		return verifyPartOfPrimaryKeys;
	}

	public static void setVerifyPartOfPrimaryKeys(boolean verifyPartOfPrimaryKeys) {
		DSSettings.verifyPartOfPrimaryKeys = verifyPartOfPrimaryKeys;
	}

	public static boolean getCreateUtilityTables() {
		return createUtilityTables;
	}

	public static boolean getUseIdInCrossTables() {
		return useIdInCrossTables;
	}

	public static void setUseIdInCrossTables(boolean useIdInCrossTables) {
		DSSettings.useIdInCrossTables = useIdInCrossTables;
	}
}
